﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using Diploma.Models;

namespace Diploma.Validation
{
    public static class Validator
    {
        public static IEnumerable<ValidationError> ValidateUserEmail(User user)
        {
            var errors = new List<ValidationError>();
            User existingUser = DataManager.Instance.UsersRepository.GetUserByEmail(user.Email, true);
            if (existingUser == null)
                return errors;
            if (user.UserId == existingUser.UserId)
                return errors;
            errors.Add(new ValidationError("Email", "Такой E-mail уже существует!"));
            return errors;
        }

        public static IEnumerable<ValidationError> ValidateStudent(Student student)
        {
            IEnumerable<ValidationError> errors = Validate(student, typeof (StudentValidationData));
            errors = errors.Concat(ValidateUserEmail(student));
            return errors;
        }

        public static IEnumerable<ValidationError> ValidateLecturer(Lecturer lecturer)
        {
            IEnumerable<ValidationError> errors = Validate(lecturer, typeof (LecturerValidationData));
            foreach (LecturersLoading loading in lecturer.LecturersLoadings)
            {
                errors = errors.Union(Validate(loading, typeof (LecturersLoadingValidationData)));
            }

            errors = errors.Concat(ValidateUserEmail(lecturer));

            return errors;
        }

        public static IEnumerable<ValidationError> ValidateTask(Task task, int planingTypeId)
        {
            IEnumerable<ValidationError> errors = Validate(task, typeof (TaskValidationData));
            if (!DataManager.Instance.TasksRepository.TaskCanBeAdded(task, planingTypeId))
                errors = errors.Concat(new[] {new ValidationError("StartDate", "Измените дату!")});

            return errors;
        }

        public static IEnumerable<ValidationError> ValidateGlobalTask(GlobalTask globalTask)
        {
            IEnumerable<ValidationError> errors = Validate(globalTask, typeof (GlobalTaskValidationData));
            if (!DataManager.Instance.GlobalTasksRepository.GlobalTaskCanBeAdded(globalTask))
                errors = errors.Concat(new[] {new ValidationError("StartDate", "Измените дату!")});

            return errors;
        }

        public static IEnumerable<ValidationError> ValidateStudentsGroup(StudentsGroup studentsGroup)
        {
            return Validate(studentsGroup, typeof (StudentsGroupValidationData));
        }

        public static IEnumerable<ValidationError> ValidateMessage(Message message)
        {
            return Validate(message, typeof (MessageValidationData));
        }

        public static IEnumerable<ValidationError> ValidatePublicMessage(PublicMessage message)
        {
            return Validate(message, typeof (PublicMessageValidationData));
        }

        public static IEnumerable<ValidationError> ValidateCollaborationRoom(CollaborationRoom room)
        {
            return Validate(room, typeof (CollaborationRoomValidationData));
        }

        private static IEnumerable<ValidationError> Validate(object instance, Type buddyType)
        {
            IEnumerable<PropertyDescriptor> buddyClassProperties =
                TypeDescriptor.GetProperties(buddyType).Cast<PropertyDescriptor>();
            IEnumerable<PropertyDescriptor> modelClassProperties =
                TypeDescriptor.GetProperties(instance.GetType()).Cast<PropertyDescriptor>();

            return from buddyProp in buddyClassProperties
                   join modelProp in modelClassProperties on buddyProp.Name equals modelProp.Name
                   from attribute in buddyProp.Attributes.OfType<ValidationAttribute>()
                   where !attribute.IsValid(modelProp.GetValue(instance))
                   select new ValidationError(buddyProp.Name, attribute.FormatErrorMessage(String.Empty));
        }
    }
}